home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Language / Compiler / allocRegs.c < prev    next >
C/C++ Source or Header  |  1990-08-16  |  21KB  |  808 lines

  1. /*
  2.  * @(#)allocRegs.c    1.6  4/11/88
  3.  */
  4. #include "assert.h"
  5. #include "regdefs.h"
  6. #include "datadesc.h"
  7. #include "allocate.h"
  8. #include "genutils.h"
  9. #include "system.h"
  10. #include "error.h"
  11. #include "trace.h"
  12. #include "option.h"
  13. #include "emit.h"
  14. #include "consts.h"
  15.  
  16. /*
  17.  * Register allocation.
  18.  */
  19.  
  20. typedef struct {
  21.   Boolean         isFree:8;
  22.   unsigned int         okBrandMask:24;
  23.   Brand             brand;
  24. } RegisterInfo;
  25.  
  26. static void TS_UpdateAIP();
  27.  
  28. RegisterInfo registers[MAXTEMPORARY - MINTEMPORARY + 1];
  29.  
  30. initializeRegisters()
  31. {
  32.   register int i;
  33.   int allBrands = 0xff;
  34.   int dataBrand = 1 << DataBrand;
  35.   int odpBrand = allBrands & ~(1 << DataBrand);
  36.  
  37.   assert((TEMPORARYREGS & LINKAGEREGS) == 0);
  38.   assert((LINKAGEREGS & ALLOCATABLEREGS) == 0);
  39.   assert((TEMPORARYREGS & ALLOCATABLEREGS) == 0);
  40.   assert((TEMPORARYREGS | ALLOCATABLEREGS | LINKAGEREGS) == 0xffff);
  41.   assert(regs_scratch >= MINTEMPORARY);
  42.   assert(regs_arg1 >= MINTEMPORARY);
  43.   assert(regs_arg2 >= MINTEMPORARY);
  44.   assert(regs_arg3 >= MINTEMPORARY);
  45.   assert(regs_scratch <= MAXTEMPORARY);
  46.   assert(regs_arg1 <= MAXTEMPORARY);
  47.   assert(regs_arg2 <= MAXTEMPORARY);
  48.   assert(regs_arg3 <= MAXTEMPORARY);
  49.   assert(regs_pc >= MINLINKAGE);
  50.   assert(regs_sp >= MINLINKAGE);
  51.   assert(regs_l >= MINLINKAGE);
  52.   assert(regs_g >= MINLINKAGE);
  53.   assert(regs_b >= MINLINKAGE);
  54.   assert(regs_ssp >= MINLINKAGE);
  55.   assert(NALLOCATABLE == 6);
  56.   assert(regs_scratch == 0);
  57.   assert(regs_arg1 == regs_scratch + 1);
  58.   assert(regs_arg2 == regs_arg1 + 1);
  59.   assert(regs_arg3 == regs_arg2 + 1);
  60.  
  61.   for (i = MINTEMPORARY; i <= MAXTEMPORARY ; i++) {
  62.     registers[i].isFree = TRUE;
  63. #ifdef vax
  64.     registers[i].okBrandMask = allBrands;
  65. #endif
  66. #ifdef sun
  67.     registers[i].okBrandMask = i < 2 ? odpBrand : dataBrand;
  68. #endif
  69.   }
  70. }
  71.  
  72. char *dummyBrandName = "Invalid";
  73. char *brandNames[] = {
  74.   "Data",
  75.   "ODP",
  76.   "Addr",
  77.   "Vector",
  78.   "Variable",
  79.   "Monitor",
  80.   "InvokeQueue",
  81.   "Unused"
  82. };
  83.  
  84. void claimReg(r_number, number, brand)
  85. int r_number, number;
  86. Brand brand;
  87. {
  88.   register int i;
  89.   TRACE3(tempreg, 3, "Claiming %d registers (starting with %s) for brand %s",
  90.     number, RN(r_number), brandNames[(int)brand]);
  91.   for (i = r_number; i < r_number + number; i++) {
  92.     if (!registers[i].isFree) {
  93.       TRACE2(tempreg, 3, "Claimed reg %s is allocated to brand %s", RN(i),
  94.     brandNames[(int)registers[i].brand]);
  95.       preemptReg(i, 1);
  96.     }
  97.     registers[i].isFree = FALSE;
  98.     registers[i].brand = (i == r_number ? brand : (Brand) -1);
  99.   }
  100. }
  101.  
  102. /*
  103.  * allocate a temporary register.  It must succeed.  If there are none
  104.  * available, then preempt one.  Try to leave the top depth elements on the
  105.  * variable stack alone.
  106.  */
  107. int forceAllocateReg(number, brand, depth)
  108. int number;
  109. Brand brand;
  110. int depth;
  111. {
  112.   int regNo, i, candidates;
  113.   register Variable *v;
  114.  
  115.   assert(number == 1);
  116.   regNo = allocateReg(number, brand);
  117.   if (regNo >= 0) return(regNo);
  118. again:
  119.   for (v = vStackTop - depth; v >= vStack && regNo < 0; v--) {
  120.     regNo = ddHasTempReg(v->data, brand);
  121.     if (regNo < 0) regNo = ddHasTempReg(v->abCon, brand);
  122.   }
  123.   if (regNo < 0 && depth > 0) {
  124.     depth = 0;
  125.     goto again;
  126.   }
  127.   if (regNo < 0) {
  128.     implementationBug("Out of temporary registers");
  129.   }
  130.   claimReg(regNo, 1, brand);
  131.   return(regNo);
  132. }
  133.  
  134. int allocateReg(number, brand)
  135. int number;
  136. Brand brand;
  137. {
  138.   register int i, j, ulimit, found = FALSE;
  139.   ulimit = MAXTEMPORARY;
  140.   ulimit -= (number - 1);  
  141.   for (i = MINTEMPORARY; i <= ulimit && !found; i++) {
  142.     found = TRUE;
  143.     for (j = 0; j < number && found; j++) {
  144.       if (!registers[i+j].isFree) found = FALSE;
  145.       if ((registers[i+j].okBrandMask & (1 << brand)) == 0) found = FALSE;
  146.     }
  147.     if (found) break;
  148.   }    
  149.   if (found) {
  150.     for (j = 0; j < number; j++) {
  151.       registers[i + j].isFree = FALSE;
  152.       registers[i + j].brand = (j == 0 ? brand : (Brand) -1);
  153.     }
  154.     TRACE3(tempreg, 2, "Wanted %d regs for brand %s, got %s", number,
  155.       brandNames[(int)brand], RN(i));
  156.     return(i);
  157.   } else {
  158.     TRACE2(tempreg, 2, "Wanted %d regs for brand %s, got none", number,
  159.       brandNames[(int)brand]);
  160.     return(-1);
  161.   }
  162. }
  163.  
  164. void freeAllRegs()
  165. {
  166.   register int i;
  167.   TRACE0(tempreg, 5, "Freeing all registers");
  168.   for (i = 0; i < MAXTEMPORARY; i++) {
  169.     if (! registers[i].isFree) {
  170.       TRACE1(tempreg, 0, "freeAllRegs: register %s is not free", RN(i));
  171.       Comment("freeAllRegs: register %s is not free", RN(i));
  172.     }
  173.     registers[i].isFree = TRUE;
  174.   }
  175. }
  176.  
  177. void freeReg(r_number, number)
  178. unsigned int r_number;
  179. int number;
  180. {
  181.   register int i;
  182.   for (i = r_number; i < r_number + number; i++) {
  183.     if (i < MINTEMPORARY || i > MAXTEMPORARY) {
  184.       TRACE1(tempreg, 1, "Freeing non-existant temp reg %d", i);
  185.     } else {
  186.       if (i == number - 1 && registers[i+1].isFree &&
  187.       registers[i+1].brand == (Brand) -1) {
  188.     TRACE1(tempreg, 1, "Freeing registers, %s got forgotten", RN(i+1));
  189.       }
  190.       if (registers[i].isFree) {
  191.     TRACE1(tempreg, 0, "Register %s is already free", RN(i));
  192.     Comment("Register %s is already free", RN(i));
  193.       } else {
  194.     TRACE2(tempreg, 3, "Freeing register %s, brand %s", RN(i),
  195.       brandNames[(int)registers[i].brand]);
  196.     registers[i].isFree = TRUE;
  197.       }
  198.     }
  199.   }
  200. }
  201.  
  202. void preemptKernelRegisters()
  203. {
  204.   preemptReg(regs_scratch, 4);
  205. }
  206.  
  207. extern NodePtr theNode;
  208.  
  209. void displayTempRegs()
  210. {
  211.   register int i;
  212.   for (i = MINTEMPORARY; i <= MAXTEMPORARY; i++) {
  213.     fprintf(stdout, "%s %s %s\n", RN(i),
  214.       registers[i].isFree ? "free" : "allocated",
  215.       brandNames[(int)registers[i].brand]);
  216.   }
  217. }
  218.  
  219. extern void vDisplayStack();
  220.  
  221. ensureAllocated(r_number, number)
  222. int r_number, number;
  223. {
  224.   register int i;
  225.   for (i = r_number; i < r_number + number; i++) {
  226.     if (registers[i].isFree) {
  227.       Comment("Register %s is used but is not allocated", RN(i));
  228.       TRACE1(tempreg, 0, "Register %s is used but it is not allocated", RN(i));
  229.       IFTRACE(tempreg, 1) {
  230.     displayTempRegs();
  231.     vDisplayStack();
  232.       }
  233.     }
  234.   }
  235. }
  236.  
  237. Boolean ddOwnsReg(d, r)
  238. DD d;
  239. int r;
  240. {
  241.   if (d.kind != DD_Address) return(FALSE);
  242.   if (d.value.address.base == Register &&
  243.       d.value.address.offset == r) return(TRUE);
  244.   if (d.value.address.base == r) return(TRUE);
  245.   if (d.value.address.hasIndex &&
  246.       d.value.address.indexReg == r) return(TRUE);
  247.   return(FALSE);
  248. }
  249.  
  250. extern Variable *vStackTop, vStack[];
  251.  
  252. void moveToTempStack(v)
  253. Variable *v;
  254. {
  255.   DD data, abCon;
  256.   
  257.   if (v->data.kind == DD_Address) {
  258.     assert(!v->data.value.address.hasIndex);
  259.   }
  260.   data.kind = DD_Address;
  261.   data.value.address = nullAddress;
  262.   data.value.address.base = regs_l;
  263.   
  264.   IFTRACE(tempreg, 1) {
  265.     trace(1, "Moving to temp stack");
  266.     displayDD(stdout, v->data , '\n');
  267.     displayDD(stdout, v->abCon, '\n');
  268.   }
  269.   if (v->abCon.kind == DD_AbCon) {
  270.     /* only do the data */
  271.     TRACE0(tempreg, 1, "Moving only the data");
  272.     data.kind = DD_Address;
  273.     data.value.address = nullAddress;
  274.     data.value.address.base = regs_l;
  275.     data.value.address.offset = TS_Allocate(4, abConToBrand(v->abCon));
  276.     emitMove(v->data, data, 'l');
  277.     freeDD(v->data);
  278.     v->data = data;
  279.   } else {
  280.     TRACE0(tempreg, 1, "Moving the data and abcon");
  281.     data.value.address.offset = TS_Allocate(8, VariableBrand);
  282.     abCon = nextAddress(data);
  283.     setDDAbstractType(abCon, getDDAbstractType(v->abCon));
  284.     ddGenerateAssign(data, abCon, v->data, v->abCon);
  285.     v->data = data;
  286.     v->abCon = abCon;
  287.   }
  288. }
  289.  
  290. void preemptReg(r_number, number)
  291. int number, r_number;
  292. {
  293.   register int i;
  294.   Variable *v;
  295.   for (i = r_number; i < r_number + number; i++) {
  296.     if (! registers[i].isFree) {
  297.       IFTRACE(tempreg, 1) {
  298.     trace(1, "Preempting register %s", RN(r_number));
  299.     displayTempRegs();
  300.     vDisplayStack();
  301.       }
  302.       for (v = vStackTop; v >= &vStack[0]; v--) {
  303.     if (ddOwnsReg(v->data, i) || ddOwnsReg(v->abCon, i)) {
  304.       moveToTempStack(v);
  305.       break;
  306.     }
  307.       }
  308.       if (!registers[i].isFree) {
  309.     ErrorMessage(theNode, "preempt register botch, save the source file\n\
  310.       and show it to norm");
  311.     freeReg((unsigned) i, 1);
  312.     Comment("Preempt register botch %s", RN(i));
  313.       }
  314.     }
  315.   }
  316. }
  317.  
  318. void eraseTempIndication(dp, reg)
  319. DD *dp;
  320. int reg;
  321. {
  322.   DD d;
  323.   d = *dp;
  324.   assert(d.kind == DD_Address);
  325.   if (d.value.address.baseIsTemporary &&
  326.       d.value.address.base == Register && 
  327.       d.value.address.offset == reg) {
  328.     d.value.address.baseIsTemporary = FALSE;
  329.   } else if (d.value.address.hasIndex &&
  330.       d.value.address.indexIsTemporary &&
  331.       d.value.address.indexReg == reg) {
  332.     d.value.address.indexIsTemporary = FALSE;
  333.   }
  334.   *dp = d;
  335. }
  336.  
  337. int ddHasTempReg(d, brand)
  338. DD d;
  339. Brand brand;
  340. {
  341.   if (d.kind != DD_Address) return(-1);
  342.   if (d.value.address.baseIsTemporary) {
  343.     if (d.value.address.base == Register &&
  344.     (registers[d.value.address.offset].okBrandMask & (1 << brand)) != 0)
  345.       return(d.value.address.offset);
  346.   } else if (d.value.address.hasIndex &&
  347.       d.value.address.indexIsTemporary &&
  348.       (registers[d.value.address.indexReg].okBrandMask & (1 << brand)) != 0) {
  349.     return(d.value.address.indexReg);
  350.   }
  351.   return(-1);
  352. }
  353.  
  354. Boolean maybeClaimReg(r_number, brand, v)
  355. int r_number;
  356. Brand brand;
  357. Variable *v;
  358. {
  359.   if (ddOwnsReg(v->data, r_number) || ddOwnsReg(v->abCon, r_number))
  360.     return(TRUE);
  361.   claimReg(r_number, 1, brand);
  362.   return(FALSE);
  363. }
  364.  
  365. /*
  366.  * Move the data part of a variable to a register.  If the register number
  367.  * is >= 0 then we insist on particular registers, otherwise any reg will do.
  368.  * Update the variable to reflect the new state.
  369.  */
  370. void moveDataToRegister(v, reg, brand)
  371. Variable *v;
  372. int reg;
  373. Brand brand;
  374. {
  375.   DD data, abcon;
  376.   int t;
  377.  
  378.   if (reg < 0) {
  379.     assert(FALSE);
  380.     if ((t = ddHasTempReg(v->data, brand)) == -1) {
  381.       t = allocateReg(1, brand);
  382.     }
  383.     data = buildRegisterDD(t);
  384.     emitMove(v->data, data, 'l');
  385.     FREEDD(v->data);
  386.     claimReg(t, 1, brand);
  387.     v->data = data;
  388.   } else {
  389.     if (ddOwnsReg(v->data, reg)) {
  390.       data = buildRegisterDD(reg);
  391.       emitMove(v->data, data, 'l');
  392.       FREEDD(v->data);
  393.       claimReg(reg, 1, brand);
  394.       v->data = data;
  395.     } else {
  396.       claimReg(reg, 1, brand);
  397.       data = buildRegisterDD(reg);
  398.       emitMove(v->data, data, 'l');
  399.       FREEDD(v->data);
  400.       v->data = data;
  401.     }
  402.   }
  403.   if (v->abCon.kind == DD_Address && 
  404.       v->abCon.value.address.base == regs_sp &&
  405.       v->abCon.value.address.autoIncrement) {
  406.     emit(POPABCON);
  407.   }
  408.   abcon.kind = DD_AbCon;
  409.   setDDConcreteType(abcon,
  410.     (v->abCon.kind == DD_AbCon ? getDDConcreteType(v->abCon) : 0)); 
  411.   setDDAbstractType(abcon, getDDAbstractType(v->abCon));
  412.   FREEDD(v->abCon);
  413.   v->abCon = abcon;
  414. }
  415.  
  416. /*
  417.  * Move a variable to a register.  If the register number
  418.  * is >= 0 then we insist on particular registers, otherwise any regs will do.
  419.  * Update the variable to reflect the new state.
  420.  */
  421. void moveVariableToRegisters(v, reg)
  422. Variable *v;
  423. int reg;
  424. {
  425.   DD data, abCon;
  426.  
  427.   assert(reg >= 0);
  428.   if (ddOwnsReg(v->data, reg)) {
  429.     data = buildRegisterDD(reg);
  430.     emitMove(v->data, data, 'l');
  431.     FREEDD(v->data);
  432.     v->data = data;
  433.     if (ddOwnsReg(v->abCon, reg+1)) {
  434.       abCon = buildRegisterDD(reg+1);
  435.       emitMove(v->abCon, abCon, 'l');
  436.       FREEDD(v->abCon);
  437.       v->abCon = abCon;
  438.       claimReg(reg, 2, VariableBrand);
  439.     } else {
  440.       claimReg(reg, 2, VariableBrand);
  441.       abCon = buildRegisterDD(reg+1);
  442.       emitMove(v->abCon, abCon, 'l');
  443.       FREEDD(v->abCon);
  444.       v->abCon = abCon;
  445.     }
  446.   } else {
  447.     claimReg(reg, 2, VariableBrand);
  448.     data = buildRegisterDD(reg);
  449.     emitMove(v->data, data, 'l');
  450.     FREEDD(v->data);
  451.     v->data = data;
  452.     abCon = buildRegisterDD(reg+1);
  453.     emitMove(v->abCon, abCon, 'l');
  454.     FREEDD(v->abCon);
  455.     v->abCon = abCon;
  456.   }
  457. }
  458.  
  459. int operationTempSize = 0, operationMaxStack = 0;
  460. int obNumber, opNumber;
  461. static AllocationInfoPtr theaip;
  462. static int localSize = 0, registerOffset;
  463. static int minimumOffset = 0;
  464. static int globalOffset, localOffset, boringOffset;
  465.  
  466. typedef struct sTSChunk {
  467.   int                 offset;
  468.   int                 size;
  469.   Boolean             isAllocated:1;
  470.   Boolean             otherHalfAllocated:1;
  471.   unsigned int             unused:14;
  472.   Brand                 brand:16;
  473.   struct sTSChunk        *next;
  474. } TSChunk, *TSChunkPtr;
  475. static TSChunkPtr head = NULL;
  476.  
  477. typedef struct sTSI {
  478.   int             saveStackSize;
  479.   struct sTSI        *prev;
  480. } TSI, *TSIPtr;
  481. static TSIPtr stack = NULL;
  482. static int stackSize = 0;
  483.  
  484. void TS_startOperation(aip, objectNumber, operationNumber)
  485. AllocationInfoPtr aip;
  486. int objectNumber, operationNumber;
  487. {
  488.   int i, lRegisterOffset;
  489.  
  490.   theaip = aip;
  491.   obNumber = objectNumber;
  492.   opNumber = operationNumber;
  493.   operationTempSize = 0;
  494.   operationMaxStack = 0;
  495.   localSize = 0;
  496.   wroteCode = TRUE;
  497.   TRACE2(tempstack, 3, "TS_startOperation op %d pass %d",
  498.     operationNumber, doGenerateCode);
  499.   if (theaip != NULL) {
  500.     localSize +=
  501.       theaip->boringSize + theaip->localSize + theaip->attachedLocalSize +
  502.       theaip->globalSize + theaip->attachedGlobalSize +
  503.       theaip->monitorSize + theaip->invokeQueueSize;
  504.     IFOPTION(allocateregisters, 1) {
  505.       registerOffset = localSize + sizeof(int);
  506.       for (i = 0; i < NALLOCATABLE; i++) {
  507.     if (theaip->regs[i].isAllocated) localSize += sizeof(int);
  508.       }
  509.     }
  510.   }
  511.   if (doGenerateCode) {
  512.     /* this is the second pass, and from aip we get what we need. */
  513.     boringOffset  = firstLocalOffset + theaip->invokeQueueSize + 
  514.       theaip->boringSize;
  515.     localOffset   = boringOffset + aip->localSize + aip->attachedLocalSize;
  516.     globalOffset  = localOffset + aip->globalSize + aip->attachedGlobalSize;
  517.  
  518.     generateEnterOperation(
  519.       aip == NULL ? sizeof(InvokeQueue) : aip->operationTempSize + localSize,
  520.       aip == NULL ? sizeof(InvokeQueue) : aip->operationMaxStack);
  521.     if (OPTION(invokequeue, 2) &&  theaip->invokeQueueSize > 0) {
  522.       emit("\tinsque\t-%d(r%d),%d(r%d)\n",
  523.     firstLocalOffset+sizeof(InvokeQueue), regs_l, GOD_ARListHead, regs_b);
  524.     }
  525.     IFOPTION(allocateregisters, 1) {
  526.       if (theaip != NULL) {
  527.     lRegisterOffset = registerOffset;
  528.     for (i = 0; i < NALLOCATABLE; i++) {
  529.       if (theaip->regs[i].isAllocated) {
  530.         lRegisterOffset += sizeof(int);
  531.       }
  532.     }
  533.     i = 0;
  534.     while (i < NALLOCATABLE) {
  535.       if (theaip->regs[i].isAllocated && 
  536.           i < NALLOCATABLE - 1 && theaip->regs[i+1].isAllocated) {
  537.         ddGenerateAssign(
  538.           buildAddressDD(regs_l, -lRegisterOffset),
  539.           buildAddressDD(regs_l, -(lRegisterOffset - 4)),
  540.           buildRegisterDDNC(i+MINALLOCATABLE),
  541.           buildRegisterDDNC(i+1+MINALLOCATABLE));
  542.         IFOPTION(nilspace, 1) ddGenerateAssign(
  543.           buildRegisterDDNC(i+MINALLOCATABLE),
  544.           buildRegisterDDNC(i+MINALLOCATABLE+1),
  545.           nilDD,
  546.           nilDD);
  547.         lRegisterOffset -= 2 * sizeof(int);
  548.         i += 2;
  549.       } else if (theaip->regs[i].isAllocated) {
  550.         emitMove(buildRegisterDDNC(i+MINALLOCATABLE), buildAddressDD(regs_l, -lRegisterOffset), 'l');
  551.         IFOPTION(nilspace, 1) emitMove(nilDD, buildRegisterDDNC(i+MINALLOCATABLE), 'l');
  552.         lRegisterOffset -= sizeof(int);
  553.         i ++;
  554.       } else {
  555.         i ++;
  556.       }
  557.     }
  558.       }
  559.     }
  560.   }
  561.   minimumOffset = localSize + firstLocalOffset;
  562.   INITIALIZEJUMPDEBUG();
  563. }
  564.  
  565. void TS_fixSPForHandler()
  566. {
  567.   emitMoveAddress(
  568.     buildAddressDD(regs_l, -(theaip->operationTempSize + localSize + 4)),
  569.     buildRegisterDDNC(regs_sp),
  570.     'l');
  571. }
  572.  
  573. extern void generateMonExit();
  574.  
  575. void TS_endOperation(monExit, initiallyDone, endRecovery)
  576. Boolean monExit, initiallyDone, endRecovery;
  577. {
  578.   TSChunkPtr p;
  579.   int lRegisterOffset, i;
  580.  
  581.   wroteCode = TRUE;
  582.   TRACE2(tempstack, 3, "TS_endOperation op %d pass %d",
  583.     opNumber, doGenerateCode);
  584.   emit("L_operationreturn_%d:\n", opNumber);
  585.   if (monExit) generateMonExit();
  586.   emit("L_operationreturnnomonexit_%d:\n", opNumber);
  587.   if (initiallyDone) generateKernelCall("em_initiallyDone");
  588.   if (endRecovery) generateKernelCall("em_endRecovery");
  589.  
  590.   IFOPTION(allocateregisters, 1) {
  591.     if (theaip != NULL) {
  592.       lRegisterOffset = registerOffset;
  593.       for (i = 0; i < NALLOCATABLE; i++) {
  594.     if (theaip->regs[i].isAllocated) {
  595.       lRegisterOffset += sizeof(int);
  596.     }
  597.       }
  598.       i = 0;
  599.       while (i < NALLOCATABLE) {
  600.     if (theaip->regs[i].isAllocated && 
  601.         i < NALLOCATABLE - 1 && theaip->regs[i+1].isAllocated) {
  602.       ddGenerateAssign(
  603.         buildRegisterDDNC(i+MINALLOCATABLE),
  604.         buildRegisterDDNC(i+1+MINALLOCATABLE),
  605.         buildAddressDD(regs_l, -lRegisterOffset),
  606.         buildAddressDD(regs_l, -(lRegisterOffset - 4)));
  607.       lRegisterOffset -= 2 * sizeof(int);
  608.       i += 2;
  609.     } else if (theaip->regs[i].isAllocated) {
  610.       emitMove(
  611.         buildAddressDD(regs_l, -lRegisterOffset),
  612.         buildRegisterDDNC(i+MINALLOCATABLE), 'l');
  613.       lRegisterOffset -= sizeof(int);
  614.       i ++;
  615.     } else {
  616.       i ++;
  617.     }
  618.       }
  619.     }
  620.   }
  621.   if (theaip == NULL) {
  622.     /* this is a process return. */
  623.     assert(operationTempSize == 0);
  624.     generateReturn(0);
  625.   } else {
  626.     generateReturn(theaip->parameterSize);
  627.   }
  628.   HSDump();
  629.   FINALIZEJUMPDEBUG();
  630.   if (theaip == NULL) {
  631.     /* do nothing */
  632.   } else {
  633.     operationMaxStack += localSize + operationTempSize;
  634.     TS_UpdateAIP();
  635.   }
  636.   emit("L_endoperation_%d:\n", opNumber);
  637. #ifdef vax
  638.   emit("\t.byte\t0\n");
  639. #endif
  640. #ifdef sun
  641.   emit("\t.word\t0\n");
  642. #endif
  643.   while (head != NULL) {
  644.     p = head;
  645.     head = head->next;
  646.     free((char *) p);
  647.   }
  648. }
  649.  
  650. void TS_StartInvocation()
  651. {
  652.   register TSIPtr t;
  653.   
  654.   TRACE0(tempstack, 5, "TS_StartInvocation");
  655.   t = (TSIPtr) calloc(sizeof(TSI), 1);
  656.   t->saveStackSize = stackSize;
  657.   t->prev = stack;
  658.   stack = t;
  659. }
  660.  
  661. void TS_Results(n)
  662. int n;
  663. {
  664.   TRACE1(tempstack, 5, "TS_Results: %d", n);
  665.   stackSize += n;
  666. }
  667.  
  668. void TS_Push()
  669. {
  670.   TRACE1(tempstack, 5, "TS_Push: %d", 8);
  671.   stackSize += 8;
  672. }
  673.  
  674. void TS_EndInvocation()
  675. {
  676.   register TSIPtr t = stack;
  677.   TRACE0(tempstack, 5, "TS_EndInvocation");
  678.   stackSize += 16 /* sizeof(DynamicLink) */;
  679.   if (stackSize > operationMaxStack) {
  680.     TRACE2(tempstack, 5, "  maxstack changed from %d to %d", operationMaxStack,
  681.       stackSize);
  682.     operationMaxStack = stackSize;
  683.   }
  684.   stackSize = t->saveStackSize;
  685.   stack = t->prev;
  686.   free((char *) t);
  687. }
  688.  
  689. int TS_Allocate(size, brand)
  690. int size;
  691. Brand brand;
  692. {
  693.   Boolean found = FALSE;
  694.   TSChunkPtr runner, trailer, p;
  695.   TRACE2(tempstack, 1, "Temp stack %d bytes for brand %s", size,
  696.     brandNames[(int)brand]);
  697.   for (runner=head, trailer=NULL;runner != NULL;trailer=runner, runner=runner->next) {
  698.     if (! runner->isAllocated &&
  699.         ! runner->otherHalfAllocated &&
  700.     runner->brand == brand) {
  701.       if (runner->size == size) {
  702.     runner->isAllocated = TRUE;
  703.     runner->otherHalfAllocated = (brand == VariableBrand);
  704.     assert(runner->brand == brand);
  705.     p = runner;
  706.     TRACE0(tempstack, 1, "Found free space to use");
  707.     found = TRUE;
  708.     break;
  709.       }
  710.     }
  711.   }
  712.   if (!found) {
  713.     p = (TSChunkPtr) malloc(sizeof(TSChunk));
  714.     p->brand = brand;
  715.     if (! doGenerateCode) {
  716.       p->offset = (trailer == NULL ? minimumOffset : trailer->offset);
  717.       p->offset += size;
  718.     } else {
  719.       switch (brand) {
  720.     case DataBrand:
  721.       p->offset = boringOffset;
  722.       boringOffset  -= size;
  723.       break;
  724.     case ODPBrand:
  725.       p->offset = localOffset;
  726.       localOffset   -= size;
  727.       break;
  728.     case VariableBrand:
  729.       p->offset = globalOffset;
  730.       globalOffset  -= size;
  731.       break;
  732.     default:
  733.       assert(FALSE);
  734.       break;
  735.       }
  736.     }
  737.     p->size = size;
  738.     p->isAllocated = TRUE;
  739.     p->otherHalfAllocated = (brand == VariableBrand);
  740.     p->next = NULL;
  741.     if (trailer == NULL) head = p; else trailer->next = p;
  742.     operationTempSize = p->offset + - minimumOffset;
  743.   }
  744.   TRACE1(tempstack, 1, "Answer is %d", -p->offset);
  745.   return(-p->offset);
  746. }
  747.  
  748. void TS_Free(offset)
  749. int offset;
  750. {
  751.   TSChunkPtr runner;
  752.   offset = -offset;
  753.   for (runner=head; runner != NULL; runner=runner->next) {
  754.     if (runner->offset == offset) {
  755.       assert(runner->isAllocated);
  756.       runner->isAllocated = FALSE;
  757.       TRACE3(tempstack, 1, "Freeing offset %d, size %d, brand %s", -offset,
  758.     runner->size, brandNames[(int)runner->brand]);
  759.       if (runner->brand == VariableBrand) {
  760.     if (runner->otherHalfAllocated) {
  761.       TRACE0(tempstack, 5, "Other half still allocated");
  762.     } else {
  763.       TRACE0(tempstack, 5, "Other half already free");
  764.     }
  765.       }
  766.       return;
  767.     } else if (runner->brand == VariableBrand && runner->offset == offset + 4) {
  768.       /* you have freed the other half of a variable */
  769.       assert(runner->otherHalfAllocated);
  770.       runner->otherHalfAllocated = FALSE;
  771.       TRACE3(tempstack, 1,"Freeing other half of offset %d, size %d, brand %s",
  772.     -offset, runner->size, brandNames[(int)runner->brand]);
  773.       return;
  774.     }
  775.   }
  776.   assert(FALSE);
  777. }
  778.  
  779. static void TS_UpdateAIP()
  780. {
  781.   TSChunkPtr runner;
  782.  
  783.   if (! doGenerateCode) {
  784.     theaip->operationTempSize = 0;
  785.     theaip->operationMaxStack = operationMaxStack;
  786.     for (runner = head; runner != NULL; runner = runner->next) {
  787.       runner->isAllocated = FALSE;
  788.       TRACE2(tempstack, 1, "brand %s bumped by %d",
  789.     brandNames[(int)runner->brand], runner->size);
  790.       switch (runner->brand) {
  791.     case DataBrand:
  792.       theaip->boringSize += runner->size;
  793.       break;
  794.     case ODPBrand:
  795.       theaip->localSize += runner->size;
  796.       break;
  797.     case VariableBrand:
  798.       theaip->globalSize += runner->size;
  799.       break;
  800.     default:
  801.       assert(FALSE);
  802.       break;
  803.       }
  804.     }
  805.   }
  806. }    
  807.  
  808.